/***************************************************************************
 *   source.c                                                              *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include "header.h"

float4 vect = MGPI_DEFAULT_VECTOR;

/**
 * Skybox transformation procedure.
 */
static void skybox_trans(MGPI_RendNode *node) {
	int hcamera = ct.component.flags[0];
    float4 eye = MGPI_DEFAULT_VECTOR;
    g3dGetCamVect(&vect, hcamera, MGPI_CAMERA_POSITION);

    glTranslatef(eye[X], eye[Y], eye[Z]);
    glScalef(1000.0f, 1000.0f, 1000.0f);
    return;
}

/**
 * User-defined rendering object transformation procedure.
 */
static void user_defined_trans(MGPI_RendNode *node) {
	glTranslatef(0, -1.5f, -10);
	glScalef(3, 3, 3);
	g3dDrawCoordinates();

	return;
}

/**
 * User-defined rendering procedure.
 */
static int user_defined(MGPI_RendNode *node) {
	Roeskva_t *ctx = (Roeskva_t *)ct.component.flags[1];

	float4 colord = { 0.1, 0.1, 0.1, 1 };
	float4 colors = { 1, 1, 1, 1 };
	int index = 0;

	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, colord);
	glLightfv(GL_LIGHT0, GL_SPECULAR, colors);
	glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0.0f);
	glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.0f);
	glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.005f);
	glMaterialf(GL_FRONT, GL_SHININESS, 100.0f);
	{
		glActiveTexture(GL_TEXTURE0);
		glMatrixMode(GL_TEXTURE);
		glPushMatrix();
		{
			glLoadIdentity();
			glScalef(3, 3, 1);

			glMatrixMode(GL_MODELVIEW);

			g3dDrawTeapot(1, -1, node->shaders.program_id);
			
			glMatrixMode(GL_TEXTURE);
		}
		glPopMatrix();
		glMatrixMode(GL_MODELVIEW);
	}
	glDisable(GL_LIGHT0);
	glDisable(GL_LIGHTING);
	return 0;
}


/**
 * Function called at the engine stop, just before shot down. In here one
 * can put the finalization code e.g. releasing resources.
 */
void ENGINE_Exit(void) {

	// And when the time comes all shall fade away...
    MGPI_ENGINE_STOP
    MGPI_Exit();

	getchar();
    return;
}

/**
 * A initialization function, called at the begining of the application. In here
 * one can put any code concerning loading objects, preparing the scene etc.
 */
void ENGINE_Init(Roeskva_t *ctx) {
	SDL_Surface *imgs[6];
	GLubyte *pixels[6];
	char *code[5];
	GLuint ids[3], targs[3] = { GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D };
	char *names[3];

    {
		// Basic definition before we start
        MGPI_ENGINE_CREATE_CAMERA(MGPI_PERSPECTIVE);
		ctx->setProperty(MGPI_CAMERA_VIEWPORT, MGPI_ENGINE_CAMERA, SCREEN_WIDTH, SCREEN_HEIGHT);

	} MGPI_ENGINE_START {
		// Configure events (NOTE: Replace any of "ct.component." with "MGPI_GetRootComponent()->" if building on Linux
		ct.component.onEvent[MGPI_KEY_DOWN] = keyProc;
		ct.component.onEvent[MGPI_MOUSE_MOTION] = mouseMotionProc;
		ct.component.onEvent[MGPI_MOUSE_BUTTON_DOWN] = mouseButtonProc;
        //MGPI_InitEvents(MGPI_THREAD_EVENTS, NULL); // Uncomment if building on Linux

		// Pass essential info to the game container
		ct.component.flags[0] = MGPI_ENGINE_CAMERA;
		ct.component.flags[1] = (int)ctx;

////////// Load the skybox //////////////////////////////////////////////////////////////////////////
		MGPI_ENGINE_HANDLE8 = ctx->loadObject(NULL, MGPI_SKYBOX_CUBEMAP);

		// Load textures for the skybox
		imgs[0] = g2dLoadImage("pos_x.tga");
		pixels[0] = imgs[0]->pixels;

		imgs[1] = g2dLoadImage("neg_x.tga");
		pixels[1] = imgs[1]->pixels;

		imgs[2] = g2dLoadImage("pos_y.tga");
		pixels[2] = imgs[2]->pixels;

		imgs[3] = g2dLoadImage("neg_y.tga");
		pixels[3] = imgs[3]->pixels;

		imgs[4] = g2dLoadImage("pos_z.tga");
		pixels[4] = imgs[4]->pixels;

		imgs[5] = g2dLoadImage("neg_z.tga");
		pixels[5] = imgs[5]->pixels;

		// Generate a single cube map texture
		MGPI_ENGINE_HANDLE0 = g3dGenTextureCubeRGB(pixels, imgs[0]->w, imgs[0]->h);

		// Setup the skybox rendering object
		ctx->selectObject(MGPI_ENGINE_HANDLE8);
		ctx->setProperty(MGPI_TRANSFORMATIONS, skybox_trans);
		ctx->setProperty(MGPI_TEXTURE, MGPI_ENGINE_HANDLE0, GL_TEXTURE_CUBE_MAP);
		
		// Free the images of the skaybox
		SDL_FreeSurface(imgs[0]);
		SDL_FreeSurface(imgs[1]);
		SDL_FreeSurface(imgs[2]);
		SDL_FreeSurface(imgs[3]);
		SDL_FreeSurface(imgs[4]);
		SDL_FreeSurface(imgs[5]);

////////// Start the shaders engine /////////////////////////////////////////////////////////////////
		ctx->setProperty(MGPI_SHADERS);

		// Load shaders code
		code[0] = (char *)fload("BumpMapping.frag");
		code[1] = (char *)fload("PhongBlinn.frag");
		code[2] = (char *)fload("mainFrag.frag");
		code[3] = (char *)fload("Tangent.vert");

		// Create and compile fragment and vertex shaders
		MGPI_ENGINE_CREATE_SHADER(MGPI_ENGINE_HANDLE0, MGPI_FRAGMENT_SHADER, 3, code, NULL);
		MGPI_ENGINE_CREATE_SHADER(MGPI_ENGINE_HANDLE1, MGPI_VERTEX_SHADER, 1, code + 3, NULL);

		// Define and select a user-defined rendering object
		MGPI_ENGINE_SELECT_NEW_OBJECT(MGPI_ENGINE_HANDLE9, MGPI_USER_DEFINED, NULL);
		ctx->setProperty(MGPI_TRANSFORMATIONS, user_defined_trans);
		ctx->setProperty(MGPI_USER_DEFINED, user_defined);

		// Configure a shader program
		ctx->selectProgram(MGPI_DEFAULT);
		MGPI_ENGINE_HANDLE2 = ctx->setupProgram(MGPI_ENGINE_HANDLES, 2);

		// Pass the program ID and effects commands to the selected rendering object
		ctx->setProperty(MGPI_SHADER_PROGRAM, MGPI_ENGINE_HANDLE2);
		ctx->setProperty(MGPI_GL_COMMANDS, MGPI_GL_CMD_COMBINED, 2, MGPI_GL_CMD_SHADERS, MGPI_GL_CMD_MULTITEXTURE);

		// Setup uniform variables loacation and value
		ctx->getProperty(MGPI_UNIFORM_LOCATION, "fvEyePosition", &MGPI_ENGINE_HANDLE3);
		ctx->setProperty(MGPI_UNIFORM_VALUE, MGPI_ENGINE_HANDLE3, MGPI_GLSL_FLOATnv, vect, 3);

		// Load textures for multitexturing
		names[0] = "bumpMap";
		ids[0] = g3dTexture2DType("mur_NormalMap.png", GL_RGB);//"upnm.png", GL_RGB);//

		names[1] = "baseMap";
		ids[1] = g3dTexture2DType("mur_Ambiant.png", GL_RGB);//"blank.jpg", GL_RGB);//

		names[2] = "specularMap";
		ids[2] = g3dTexture2DType("mur_Hauteur.png", GL_RGB);//"black.jpg", GL_RGB);//

		// Pass the taxtures to the selected rendering object
		ctx->setProperty(MGPI_MULTITEXTURE, 3, names, targs, ids);

		// Don't show the cursor
		SDL_ShowCursor(SDL_DISABLE);
	}
    return;
}

/**
 * The engine main rendering loop function. Place here any code refering
 * to rendering process. Note that calling here any logic processing functions
 * is not advisable.
 */
void ENGINE_Render(Roeskva_t *ctx) {
	float4 pos = MGPI_DEFAULT_VECTOR;
	pos[X] = posX * 10;
	pos[Y] = posY * 10;
	pos[Z] = posZ * 10;

	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);
	glLightfv(GL_LIGHT0, GL_POSITION, pos);
	glDisable(GL_LIGHT0);
	glDisable(GL_LIGHTING);
	
	g3dGetCamVect(&vect, ctx->hcamera, MGPI_CAMERA_POSITION);
    ctx->updateCamera(MGPI_ENGINE_CAMERA);
    {
		// Render skybox
		ctx->renderObject(MGPI_ENGINE_HANDLE8);

		// Render surface with bumpmapping
		ctx->renderObject(MGPI_ENGINE_HANDLE9);

		// Render global triad and white grid
		g3dDrawCoordinates();
		g3dDrawGrid(50.0f, 1.0f, -2.0f, 1, 1, 1);

		// Render diagnostic informations
		ctx->renderDiagnostic();
		SDL_Delay(12);
    }
    ctx->commitChanges();
    return;
}
